package logic.gridSimInterface.brokers;

import eduni.simjava.Sim_event;
import gridsim.GridSim;
import gridsim.GridSimTags;
import gridsim.ResourceCharacteristics;
import gridsim.net.SimpleLink;
import java.util.LinkedList;
import java.util.Vector;
import logic.JSimulation;
import logic.gridNodes.GridResource;
import logic.gridSimInterface.SimTags;
import logic.gridSimInterface.resource.ResourceCharacteristicExt;
import logic.gridSimInterface.user.GridletInfo;

public abstract class AbstractBroker extends GridSim {

    /**
     * Meno nadradeneho brokera, moze byt aj null.
     */
    private String ownerName;

    public AbstractBroker(String name, SimpleLink link, String owner) throws Exception {
        super(name, link);
        setOwnerName(owner);
    }

    public final String getOwnerName() {
        return ownerName;
    }

    protected final void setOwnerName(final String val) {
        this.ownerName = val;
    }

    /**
     * Pripravene na buduce rozsirenie - zavola sa, ak pride sprava o zmene stavu
     * zdroja.
     */
    protected void resourceStatusChanged(int resourceID, boolean goesOnline) {
    }

    /**
     * Pripravene na buduce pouzitie.
     */
    protected void userStatusChanged(int userID, boolean goesOnline) {
    }

    public abstract void body();

    /**
     * Ak pride sprava neznameho typu, zavola sa tato metoda.
     * @return true, ak entita dokaze obsluzit spravu daneho typu.
     */
    protected boolean handleMessage(Sim_event ev) {
        return false;
    }
    
    /**
     * Ziskanie informacii o priradenych zdrojoch z GIS.
     * @param resourcesID   zoznam identifikatorov priradenych zdrojov
     * @return              zoznam informacii o priradenych zdrojoch
     */
    protected LinkedList<ResourceCharacteristicExt> getResourcesInfo(Vector<Integer> resourcesID) {
        int myResourcesCount = resourcesID.size();
        LinkedList<ResourceCharacteristicExt> result = 
                new LinkedList<ResourceCharacteristicExt>();
        //ture <=> info o zdroji [i] uz dorazilo
        boolean[] pridane = new boolean[myResourcesCount];
        for (int i = 0; i < myResourcesCount; i++) {
            pridane[i] = false;
            result.add(null);
        }
        int recievedCharacteristicsCount = 0;
        while (recievedCharacteristicsCount < myResourcesCount) {
            gridSimHold(1.0);
            for (int i = 0; i < myResourcesCount; i++)
                if (!pridane[i]) {
                    ResourceCharacteristics res = getResourceCharacteristics(resourcesID.get(i));
                    if (res != null) {
                        if (res instanceof ResourceCharacteristicExt) {
                            result.set(i, (ResourceCharacteristicExt)res);
                            recievedCharacteristicsCount++;
                            pridane[i] = true;
                        };
                    }
                };
        }
        
        return result;
    }
    
    /**
     * Odosle vlastnikovi gridletu spravu UNABLE_TO_PROCESS_GRIDLET.
     */
    protected void sendUnableToProcessMessage(GridletInfo g) {
        super.send(g.getUserId(),
                   GridSimTags.SCHEDULE_NOW,
                   SimTags.UNABLE_TO_PROCESS_GRIDLET,
                   g);
    }
    
    /**
     * Cakanie na prichod spravy SIMULATION_START.
     */
    protected void waitForStart() {
        Sim_event ev = new Sim_event();
        boolean odstartovane = false;
        do {
            sim_get_next(ev);
            odstartovane = (ev.get_tag() == SimTags.SIMULATION_START);
        } while (!odstartovane);
    }
    
    
    /**
     * Poslanie BROKER_READY vlastnikovi. Ak owner == null, posle to Hermesovi.
     */
    protected void sendReadyToOwner(Vector<Integer> resourcesID) {
        if (getOwnerName() == null)
            super.send(JSimulation.getHermesName(),
                    GridSimTags.SCHEDULE_NOW, SimTags.BROKER_READY);
        else
            super.send(getOwnerName(),
                    GridSimTags.SCHEDULE_NOW, SimTags.BROKER_READY,
                    new Vector<Integer>(resourcesID));
    }
}
